/*
* Copyright (c) 2007 by Kirill Kolodyazhniy.
* See the file "license.terms" for information on usage and redistribution.
*/

#ifdef _WIN32
#include <windows.h>
#include "directx/dxrendersystem.h"
#endif

#include "octree/octreescenemanager.h"
#include "ode/odephysicsystem.h"
#include "scenemanager.h"
#include "graphic.h"
#include "light.h"
#include "entity.h"
#include "particlesystem.h"

#ifdef _DEBUG
#ifdef _MSC_VER
   #define new new( _CLIENT_BLOCK, __FILE__, __LINE__)
#endif
#endif // _DEBUG

namespace Engine
{
	/**********************************************************************************************************/
	template<> Graphic* Singleton<Graphic>::m_singleton = 0;
	/**************************************************************************************************************/
	Graphic::Graphic()
	{
		//register scene managers factories
		RefPtr<SceneManagerFactory,WeakPtrExtension> smfactory (new SceneManagerFactory());
		m_sceneManagerFactories.insert(SceneManagerFactoriesMap::value_type(smfactory->GetType(),smfactory));
		RefPtr<SceneManagerFactory,WeakPtrExtension> osmfactory ( new OctreeSceneManagerFactory());
		m_sceneManagerFactories.insert(SceneManagerFactoriesMap::value_type(osmfactory->GetType(),osmfactory));


		//register render systems factories
#ifdef _WIN32
		RefPtr<RenderSystemFactory,WeakPtrExtension> dxfactory (new DXRenderSystemFactory());
		m_renderSystemFactories.insert(RenderSystemFactoriesMap::value_type(dxfactory->GetType(),dxfactory));
#else
		GLRenderSystemFactory* glfactory = new GLRenderSystemFactory();
		m_renderSystemFactories.insert(RenderSystemFactoriesMap::value_type(glfactory->GetType(),glfactory));
#endif

		//register movable objects factories.
		RefPtr<MovableObjectFactory,WeakPtrExtension> lightFactory ( new LightFactory());
		m_movableObjectFactories.insert(MovableObjectFactoriesMap::value_type(lightFactory->GetType(),lightFactory));
		RefPtr<MovableObjectFactory,WeakPtrExtension> entityFactory ( new EntityFactory());
		m_movableObjectFactories.insert(MovableObjectFactoriesMap::value_type(entityFactory->GetType(),entityFactory));
		RefPtr<MovableObjectFactory,WeakPtrExtension> particleSystemFactory ( new ParticleSystemFactory());
		m_movableObjectFactories.insert(MovableObjectFactoriesMap::value_type(particleSystemFactory->GetType(),particleSystemFactory));

		//register physic systems
		RefPtr<PhysicSystemFactory,WeakPtrExtension> odePhysicFactory ( new OdePhysicSystemFactory());
		m_physicSystemFactories.insert(PhysicSystemFactoriesMap::value_type(odePhysicFactory->GetType(),odePhysicFactory));


		Log::GetSingleton() << "Graphic constructed" << std::endl;
	}
	/**************************************************************************************************************/
	Graphic::~Graphic()
	{
	}
	/**************************************************************************************************************/
	void Graphic::ProcessMessages()
	{
#ifdef _WIN32
		MSG  msg;
		while( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
		{
			TranslateMessage( &msg );
			DispatchMessage( &msg );
		}
#endif
	}
	/**************************************************************************************************************/
	void Graphic::RenderOneFrame()
	{
		unsigned long frameStart = m_timer.GetMilliseconds();
		FrameStartSignal(frameStart - m_frameEndTime);

		ProcessMessages();
        UpdateAllRenderTargets();

		m_frameEndTime = m_timer.GetMilliseconds();
        FrameEndSignal(m_frameEndTime - frameStart);
	}
	/**************************************************************************************************************/
	void Graphic::UpdateAllRenderTargets()
	{
		m_renderSystem->UpdateAllRenderTargets();
	}
	/**************************************************************************************************************/
	SceneManagerPtr Graphic::CreateSceneManager(const std::string& type, const std::string& name)
	{
		SceneManagerFactoriesMap::iterator fact = m_sceneManagerFactories.find(type);
		if(fact != m_sceneManagerFactories.end())
		{
			RefPtr<SceneManager,WeakPtrExtension> mngr (fact->second->CreateInstance(name));
			m_sceneManagers.insert(SceneManagerMap::value_type(mngr->GetName(),mngr));
		}
		Log::GetSingleton() << "Scene manager created : " << type << " " << name << std::endl;
		return m_sceneManagers[name];
	}
	/**************************************************************************************************************/
	PhysicSystemPtr Graphic::CreatePhysicSystem(const std::string& type, const std::string& name)
	{
		PhysicSystemFactoriesMap::iterator fact = m_physicSystemFactories.find(type);
		if(fact != m_physicSystemFactories.end())
		{
			RefPtr<PhysicSystem,WeakPtrExtension> psyst (fact->second->CreateInstance(name));
			m_physicSystems.insert(PhysicSystemMap::value_type(psyst->GetName(),psyst));
		}
		Log::GetSingleton() << "Physic System created : " << type << " " << name << std::endl;
		return m_physicSystems[name];
	}
	/**************************************************************************************************************/
	RenderSystemPtr Graphic::CreateRenderSystem(const std::string& type)
	{
		RenderSystemFactoriesMap::iterator fact = m_renderSystemFactories.find(type);
		if(fact != m_renderSystemFactories.end())
		{
			m_renderSystem = RefPtr<RenderSystem, WeakPtrExtension>(fact->second->CreateInstance(""));
			Log::GetSingleton() << "Render system created : " << type << std::endl;
		}
		return m_renderSystem;
	}
	/**************************************************************************************************************/
	MovableObjectFactoryPtr Graphic::GetMovableObjectFactory(const std::string& type)
	{
		MovableObjectFactoriesMap::iterator fact = m_movableObjectFactories.find(type);
		if(fact != m_movableObjectFactories.end())
		{
			return fact->second;
		}
		return MovableObjectFactoryPtr();
	}
	/**************************************************************************************************************/
}
